package lib.api.bierdopje;

import java.util.ArrayList;
import java.util.List;

import lib.XML.XMLHelper;
import lib.api.XmlHTTPAPI;
import lib.api.bierdopje.model.JBierEpisode;
import lib.api.bierdopje.model.JBierShow;
import lib.api.bierdopje.model.JBierSubtitle;
import lib.logging.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class JBierdopjeApi extends XmlHTTPAPI{

    private String apiKey, apiServer;

    public JBierdopjeApi(String apiKey) {
        this(apiKey, "http://api.bierdopje.com");
        this.setUserAgent("JBierSubDownloader/4.0.17");
        this.setRatelimit(10);
        this.setDayRatelimit(300);
    }

    public JBierdopjeApi(String apiKey, String apiServer) {
        this.setApiKey(apiKey);
        this.setApiServer(apiServer);
    }

    public JBierEpisode GetEpisodeById(int episodeid) throws BierdopjeException {
        Document doc;
        //timeout 45 days
        doc = getXMLDisk(createApiUrl("GetEpisodeById", new String[]{Integer.toString(episodeid)}), 24 * 60 * 60 * 45);
        NodeList nList = doc.getElementsByTagName("response");

        if (nList.getLength() > 0
                && nList.item(0).getNodeType() == Node.ELEMENT_NODE) {
            return parseEpisodeNode((Element) nList.item(0));
        }

        return null;
    }

    private String createApiUrl(String command, String[] params) {
    	Logger.instance.trace("JBierdopjeApi", "createApiUrl", "");
        command = command.replace("/", "");
        String urlParam = "";
        for (int i = 0; i < params.length; i++) {
            if (i == 0) {
                urlParam = params[i].replace("/", "");
            } else {
                urlParam = urlParam + "/" + params[i].replace("/", "");
            }
        }
        Logger.instance.trace("JBierdopjeApi", "createApiUrl", "create part: " + "/" + command + "/" + urlParam);
        return this.apiServer + "/" + this.getApiKey() + "/" + command + "/" + urlParam;
        //return this.apiServer + "/" + this.getApiKey() + "/" + command + "/" + URLEncoder.encode(urlParam, "UTF-8");
    }

    private JBierEpisode parseEpisodeNode(Element eElement) {
    	Logger.instance.trace("JBierdopjeApi", "parseEpisodeNode", "");

    	try {
			Logger.instance.trace("JBierdopjeApi", "parseEpisodeNode", "Element: " + XMLHelper.getXMLAsString(eElement));
		} catch (Exception e) {		}
		
        JBierEpisode ep = new JBierEpisode();
        ep.setAirdate(XMLHelper.getStringTagValue("airdate", eElement));
        ep.setSubsen(XMLHelper.getBooleanTagValue("subsen", eElement));
        ep.setSubsnl(XMLHelper.getBooleanTagValue("subsnl", eElement));
        ep.setEpisode(XMLHelper.getIntTagValue("episode", eElement));
        ep.setEpnumber(XMLHelper.getIntTagValue("epnumber", eElement));
        ep.setFormatted(XMLHelper.getStringTagValue("formatted", eElement));
        ep.setEpisodeid(XMLHelper.getIntTagValue("episodeid", eElement));
        ep.setEpisodelink(XMLHelper.getStringTagValue("episodelink", eElement));
        ep.setSeason(XMLHelper.getIntTagValue("season", eElement));
        ep.setIsSpecial(XMLHelper.getStringTagValue("is_special", eElement));
        ep.setTitle(XMLHelper.getStringTagValue("title", eElement));
        ep.setVotes(XMLHelper.getStringTagValue("votes", eElement));
        ep.setWip(XMLHelper.getStringTagValue("wip", eElement));
        ep.setWipuser(XMLHelper.getStringTagValue("wipuser", eElement));
        ep.setWippercentage(XMLHelper.getIntTagValue("wippercentage", eElement));
        ep.setSummary(XMLHelper.getStringTagValue("summary", eElement));
        ep.setTvdbid(XMLHelper.getIntTagValue("tvdbid", eElement));
        ep.setScore(XMLHelper.getStringTagValue("score", eElement));

        return ep;
    }

    public JBierShow FindShowByName(String showname) throws BierdopjeException {
    	Logger.instance.trace("JBierdopjeApi", "FindShowByName", "showname: " + showname);
        Document doc;
        String searchterm = XMLHelper.CleanBadChars(showname);
        final String url = createApiUrl("FindShowByName", new String[]{searchterm.replace(" ", "-").replace("&", "_")});
        doc = getXMLDisk(url);

        //remove chars to clean up inconsistencies in show names
        showname = cleanUpShowNames(showname);

        NodeList nList = doc.getElementsByTagName("result");

        for (int i = 0; i < nList.getLength(); i++) {
            if (nList.item(i).getNodeType() == Node.ELEMENT_NODE && !nList.item(i).getParentNode().getNodeName().equals("genres")) {
                Element eElement = (Element) nList.item(i);
                if (eElement != null) {
                    JBierShow s = parseShowNode(eElement);
                    //remove same chars as in showname
                    String biershow = cleanUpShowNames(s.getName());
                    //replace HTML chars
                    biershow = biershow.replace("&amp;", "&").replace("'", "");
                    if (biershow.compareToIgnoreCase(showname) == 0) {
                        //store entry
                        return s;
                    }
                }
            }
        }
        
        try {
            Logger.instance.trace("JBierdopjeApi", "FindShowByName", "Unable to Parse, Response from Bierdopje: " + XMLHelper.getXMLAsString(doc));
        } catch (Exception e) {
        	//do nothing
        }
        
        return null;
    }

    private String cleanUpShowNames(String text) {
    	Logger.instance.trace("JBierdopjeApi", "cleanUpShowNames", "text: " + text);
        return text.replace("(", "").replace(")", "").replace(":", "").replace("'", "").replace("?", "").replace(".", "").replace("- ", "");
    }

    public List<JBierEpisode> GetAllEpisodesForShow(int showid) throws BierdopjeException {
        List<JBierEpisode> epList = new ArrayList<JBierEpisode>();

        //timeout 7 days
        Document doc = getXMLDisk(createApiUrl("GetAllEpisodesForShow", new String[]{Integer.toString(showid)}), 24 * 60 * 60 * 7);

        NodeList nList = doc.getElementsByTagName("result");

        for (int i = 0; i < nList.getLength(); i++) {
            if (nList.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element eElement = (Element) nList.item(i);
                JBierEpisode ep = parseEpisodeNode(eElement);
                epList.add(ep);
            }
        }

        return epList;
    }

    public List<JBierEpisode> GetEpisodesForSeason(int showid, int season) throws BierdopjeException {
        List<JBierEpisode> epList = new ArrayList<JBierEpisode>();

        //timeout 3 hours  60 * 60 * 3
        //timeout 15 days 24 * 60 * 60 * 15
        //timeout 7 days 24 * 60 * 60 * 7
        
        String seasonString;
        if (season == 0){
        	seasonString = "00";
        }else{
        	seasonString = Integer.toString(season);
        }
        
        Document doc = getXMLDisk(createApiUrl("GetEpisodesForSeason",
                new String[]{Integer.toString(showid), seasonString}), 24 * 60 * 60 * 14); 

        NodeList nList = doc.getElementsByTagName("result");

        for (int i = 0; i < nList.getLength(); i++) {
            if (nList.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element eElement = (Element) nList.item(i);
                JBierEpisode ep = parseEpisodeNode(eElement);
                epList.add(ep);
            }
        }

        return epList;
    }

    public JBierShow GetShowById(int showid) throws BierdopjeException {
    	Logger.instance.trace("JBierdopjeApi", "GetShowById", "showid: " + showid);
        //timeout 45 days
        Document doc = getXMLDisk(createApiUrl("GetShowById", new String[]{Integer.toString(showid)}), 24 * 60 * 60 * 45);

        NodeList nList = doc.getElementsByTagName("response");

        if (nList.getLength() > 0
                && nList.item(0).getNodeType() == Node.ELEMENT_NODE) {
            return parseShowNode((Element) nList.item(0));
        }
        try {
            Logger.instance.trace("JBierdopjeApi", "GetShowById", "Unable to Parse, Response from Bierdopje: " + XMLHelper.getXMLAsString(doc));
        } catch (Exception e) {
        	//do nothing
        }
        return null;

    }

    public JBierShow GetShowByTVDBID(int showid) throws BierdopjeException {
        //timeout 45 days
        Document doc = getXMLDisk(createApiUrl("GetShowByTVDBID", new String[]{Integer.toString(showid)}), 24 * 60 * 60 * 45);

        NodeList nList = doc.getElementsByTagName("response");

        if (nList.getLength() > 0
                && nList.item(0).getNodeType() == Node.ELEMENT_NODE) {
            return parseShowNode((Element) nList.item(0));
        }
        return null;

    }

    private JBierShow parseShowNode(Element eElement) {
    	Logger.instance.trace("JBierdopjeApi", "parseShowNode", "");
    	try {
			Logger.instance.trace("JBierdopjeApi", "parseShowNode", "Element: " + XMLHelper.getXMLAsString(eElement));
		} catch (Exception e) {		}
		
        JBierShow show = new JBierShow();

        show.setName(XMLHelper.getStringTagValue("showname", eElement));
        show.setAirtime(XMLHelper.getStringTagValue("airtime", eElement));
        show.setEpisodes(XMLHelper.getIntTagValue("episodes", eElement));
        show.setFavorites(XMLHelper.getStringTagValue("favorites", eElement));
        show.setFirststaired(XMLHelper.getStringTagValue("firstaired", eElement));
        show.setLink(XMLHelper.getStringTagValue("showlink", eElement));
        show.setNetwork(XMLHelper.getStringTagValue("network", eElement));
        show.setNextepisode(XMLHelper.getStringTagValue("nextepisode", eElement));
        show.setRuntime(XMLHelper.getStringTagValue("runtime", eElement));
        show.setShowid(XMLHelper.getIntTagValue("showid", eElement));
        show.setSeasons(XMLHelper.getIntTagValue("seasons", eElement));
        show.setShowstatus(XMLHelper.getStringTagValue("showstatus", eElement));
        show.setHasTranslators(XMLHelper.getBooleanTagValue("has_translators", eElement));
        show.setSummary(XMLHelper.getStringTagValue("summary", eElement));
        show.setTvdbid(XMLHelper.getIntTagValue("tvdbid", eElement));
        show.setScore(XMLHelper.getStringTagValue("score", eElement));
        
        Logger.instance.trace("JBierdopjeApi", "parseShowNode", "Return show: " + show.getName());
        return show;
    }

    public List<JBierSubtitle> GetAllSubsForEpisode(int episodeid,
                                                    String LanguageCode)  throws BierdopjeException  {
        List<JBierSubtitle> subList = new ArrayList<JBierSubtitle>();
        //Document doc = getXML(this.apiServer + "/" + this.getApiKey() + "/GetAllSubsForEpisode/" + episodeid + "/" +  LanguageCode);
        Document doc = getXML(createApiUrl("GetAllSubsForEpisode", new String[]{Integer.toString(episodeid), LanguageCode}));

		if (doc != null) {
			NodeList nList = doc.getElementsByTagName("result");

			for (int i = 0; i < nList.getLength(); i++) {
				if (nList.item(0).getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nList.item(i);
					JBierSubtitle ep = parseSubtitleNode(eElement);
					subList.add(ep);
				}
			}
		}
        
        return subList;

    }

    public List<JBierSubtitle> GetSubsForSeason(int showid, int season, String LanguageCode) throws BierdopjeException {
        List<JBierSubtitle> subList = new ArrayList<JBierSubtitle>();
        
        String seasonString;
        if (season == 0){
        	seasonString = "00";
        }else{
        	seasonString = Integer.toString(season);
        }
        
        Document doc = getXML(createApiUrl("GetSubsForSeason", new String[]{Integer.toString(showid), seasonString, LanguageCode}));

        NodeList nList = doc.getElementsByTagName("result");

        for (int i = 0; i < nList.getLength(); i++) {
            if (nList.item(0).getNodeType() == Node.ELEMENT_NODE) {
                Element eElement = (Element) nList.item(i);
                JBierSubtitle ep = parseSubtitleNode(eElement);
                subList.add(ep);
            }
        }

        return subList;

    }

    private JBierSubtitle parseSubtitleNode(Element eElement) {
    	Logger.instance.trace("JBierdopjeApi", "parseSubtitleNode", "");

    	try {
			Logger.instance.trace("JBierdopjeApi", "parseSubtitleNode", "Element: " + XMLHelper.getXMLAsString(eElement));
		} catch (Exception e) {		}
		
    	
        JBierSubtitle subtitle = new JBierSubtitle();

        subtitle.setFilename(XMLHelper.getStringTagValue("filename", eElement));
        subtitle.setDownloadcount(XMLHelper.getIntTagValue("numdownloads", eElement));
        subtitle.setDownloadlink(XMLHelper.getStringTagValue("downloadlink", eElement));
        subtitle.setFilesize(XMLHelper.getStringTagValue("filesize", eElement));
        subtitle.setPubdate(XMLHelper.getStringTagValue("pubdate", eElement));
        subtitle.setRepliescount(XMLHelper.getStringTagValue("numreplies", eElement));
        subtitle.setUploader(XMLHelper.getStringTagValue("uploader", eElement));

        return subtitle;
    }

    public void setApiKey(String apiKey) {
        this.apiKey = apiKey;
    }

    public String getApiKey() {
        return apiKey;
    }

    public void setApiServer(String apiServer) {
        this.apiServer = apiServer;
    }

    public String getApiServer() {
        return apiServer;
    }

    private Document checkDocumentForError(Document doc, String url) throws BierdopjeException {
        NodeList nList = doc.getElementsByTagName("error_code");
        if (nList.getLength() == 0){
            return doc;
        }else{
            removeCacheEntry(url);
            String xmlString = "XML could not be parsed to String";
            try {
				xmlString = XMLHelper.getXMLAsString(doc);
			} catch (Exception e) {	}
			throw new BierdopjeException("Error Code found in the anwser from bierdopje", xmlString);
        }
    }

    protected Document getCheckedXML(String url)  throws BierdopjeException {
        setUserAgent("JBierSubDownloader/4.0.9");
        setRatelimit(10);
        Document doc = getXML(url);
        return checkDocumentForError(doc, url);
    }

    protected Document getCheckedXML(String url, long timeout)  throws BierdopjeException {
    	setUserAgent("JBierSubDownloader/4.0.9");
        setRatelimit(10);
        Document doc = getXML(url, timeout);
        return checkDocumentForError(doc, url);
    }

    protected Document getCheckedXMLDisk(String url)  throws BierdopjeException {
    	setUserAgent("JBierSubDownloader/4.0.9");
        setRatelimit(10);
        Document doc = getXMLDisk(url);
        return checkDocumentForError(doc, url);
    }

    protected Document getCheckedXMLDisk(String url, long timeout)  throws BierdopjeException {
    	setUserAgent("JBierSubDownloader/4.0.9");
        setRatelimit(10);
        Document doc = getXMLDisk(url, timeout);
        return checkDocumentForError(doc, url);
    }
}
